home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiscKit1.7.1
/
MiscKitArchive.mbox
/
Re__MiscMatrix_bugs_.attach
/
MiscMatrix.m
< prev
Wrap
Text File
|
1994-07-07
|
16KB
|
677 lines
//
// MiscMatrix.m -- a class to implement variable-sized matrices
// Written by Mike Ferris (c) 1994 by Mike Ferris.
// Modified from original MOKit "MOMatrix" class by Don Yacktman.
// Version 1.0. All rights reserved.
//
// This notice may not be removed from this source code.
//
// This object is included in the MiscKit by permission from the author
// and its use is governed by the MiscKit license, found in the file
// "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
// for a list of all applicable permissions and restrictions.
//
// MiscMatrix is a subclass of Matrix that allows independantly sizable
// rows and columns. Each row can have a different height and each column
// can have a different width.
#import <misckit/MiscMatrix.h>
#import <objc/objc-runtime.h>
#define CLASS_VERSION 0
#define CLASS_NAME "MiscMatrix"
// These are the private methods we use in MiscMatrix
@interface MiscMatrix(private)
- _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone;
- _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col;
- _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row;
@end
@implementation MiscMatrix
+ initialize
// Set the class version
{
if (self == objc_lookUpClass(CLASS_NAME)) {
[self setVersion:CLASS_VERSION];
}
return self;
}
- setupStorage:(int)rowsHigh :(int)colsWide
// Set up our storage objects
{
int i;
MiscColumnSize newCSize;
MiscRowSize newRSize;
columnSizes = [[Storage allocFromZone:[self zone]] initCount:0
elementSize:sizeof(MiscColumnSize)
description:MISC_COLUMNSIZE_DESC];
rowSizes = [[Storage allocFromZone:[self zone]] initCount:0
elementSize:sizeof(MiscRowSize)
description:MISC_ROWSIZE_DESC];
newCSize.width = cellSize.width;
newRSize.height = cellSize.height;
for (i=0; i<colsWide; i++) {
newCSize.x = bounds.origin.x + (i*cellSize.width) +
(i*intercell.width);
[columnSizes addElement:&newCSize];
}
for (i=0; i<rowsHigh; i++) {
newRSize.y = bounds.origin.y + (i*cellSize.height) +
(i*intercell.height);
[rowSizes addElement:&newRSize];
}
return self;
}
- initFrame:(const NXRect *)frm mode:(int)aMode prototype:cellId
numRows:(int)rowsHigh numCols:(int)colsWide
// Designated initializer override from Matrix. Sets up our storage stuff.
{
[super initFrame:frm mode:aMode prototype:cellId numRows:numRows
numCols:numCols];
[self setupStorage:rowsHigh :colsWide];
return self;
}
- initFrame:(const NXRect *)frm mode:(int)aMode cellClass:factoryId
numRows:(int)rowsHigh numCols:(int)colsWide
// Designated initializer override from Matrix. Sets up our storage stuff.
{
[super initFrame:frm mode:aMode cellClass:factoryId numRows:numRows
numCols:numCols];
[self setupStorage:rowsHigh :colsWide];
return self;
}
- _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone
{
rowSizes = [rs copyFromZone:zone];
columnSizes = [cs copyFromZone:zone];
return self;
}
- copyFromZone:(NXZone *)zone
{
id obj = [super copyFromZone:zone];
[obj _Misc_copyRowSizes:rowSizes andColSizes:columnSizes zone:zone];
return obj;
}
- free
// free the storage
{
[columnSizes free];
[rowSizes free];
return [super free];
}
- _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col
// A private method used by the methods which cause sizing stuff to change
{
int i;
if ((col < 0) || (col >= numCols)) {
return nil;
}
for (i=col; i<numCols; i++) {
MiscColumnSize *cSize;
cSize = (MiscColumnSize *)[columnSizes elementAt:i];
if (cSize) cSize->x += difference;
}
return self;
}
- _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row
// A private method used by the methods which cause sizing stuff to change
{
int i;
if ((row < 0) || (row >= numRows)) {
return nil;
}
for (i=row; i<numRows; i++) {
MiscRowSize *rSize;
rSize = (MiscRowSize *)[rowSizes elementAt:i];
if (rSize) rSize->y += difference;
}
return self;
}
- setWidth:(NXCoord)newWidth ofCol:(int)col
// This method allows the setting of column widths
{
NXCoord diff;
MiscColumnSize *cSize;
if ((col < 0) || (col >= numCols)) {
return nil;
}
cSize = (MiscColumnSize *)[columnSizes elementAt:col];
diff = newWidth - cSize->width;
cSize->width = newWidth;
[self _Misc_moveColumnsRightBy:diff startingAt:col+1];
return self;
}
- setHeight:(NXCoord)newHeight ofRow:(int)row
// This method allows the setting of row heights
{
NXCoord diff;
MiscRowSize *rSize;
if ((row < 0) || (row >= numRows)) {
return nil;
}
rSize = (MiscRowSize *)[rowSizes elementAt:row];
diff = newHeight - rSize->height;
rSize->height = newHeight;
[self _Misc_moveRowsDownBy:diff startingAt:row+1];
return self;
}
- sizeToCells
// Resize the matrix to the proper size to fit all our cells.
{
NXRect rect;
MiscColumnSize *cSize;
MiscRowSize *rSize;
[self getFrame:&rect];
if (numCols == 0) {
rect.size.width = 0.0;
} else {
cSize = (MiscColumnSize *)[columnSizes lastElement];
rect.size.width = cSize->x + cSize->width - bounds.origin.x;
}
if (numRows == 0) {
rect.size.height = 0.0;
} else {
rSize = (MiscRowSize *)[rowSizes lastElement];
rect.size.height = rSize->y + rSize->height - bounds.origin.y;
}
[self setFrame:&rect];
return self;
}
- renewRows:(int)newRows cols:(int)newCols
// Makes sure to keep our storage objects in synch with everything else.
{
MiscColumnSize newCSize, *cSize;
MiscRowSize newRSize, *rSize;
int i;
// Remove any storage elements past the new number of cols
for (i=numCols-1; i>=newCols; i--) {
[columnSizes removeLastElement];
}
// Add any needed new storage elements to get up to the new number of cols
for (i=numCols; i<newCols; i++) {
if (i==0) {
newCSize.x = bounds.origin.x;
} else {
cSize = (MiscColumnSize *)[columnSizes lastElement];
newCSize.x = cSize->x + cSize->width + intercell.width;
}
newCSize.width = cellSize.width;
[columnSizes addElement:&newCSize];
}
// Remove any storage elements past the new number of rows
for (i=numRows-1; i>=newRows; i++) {
[rowSizes removeLastElement];
}
// Add any needed new storage elements to get up to the new number of rows
for (i=numRows; i<newRows; i++) {
if (i==0) {
newRSize.y = bounds.origin.y;
} else {
rSize = (MiscRowSize *)[rowSizes lastElement];
newRSize.y = rSize->y + rSize->height + intercell.height;
}
newRSize.height = cellSize.height;
[rowSizes addElement:&newRSize];
}
[super renewRows:newRows cols:newCols];
return self;
}
- insertColAt:(int)col
// Keep the storage in synch
{
MiscColumnSize newCSize, *cSize;
if (col < 0) {
return nil;
}
if (col <= numCols) {
[super insertColAt:col];
if (col > 0) {
cSize = (MiscColumnSize *)[columnSizes elementAt:col];
newCSize.x = cSize->x;
} else {
newCSize.x = bounds.origin.x;
}
newCSize.width = cellSize.width;
[columnSizes insertElement:&newCSize at:col];
[self _Misc_moveColumnsRightBy:newCSize.width + intercell.width
startingAt:col+1];
} else {
return nil;
}
return self;
}
- insertRowAt:(int)row
// Keep the storage in synch
{
MiscRowSize newRSize, *rSize;
if ((row < 0) || (row > numRows))
return nil;
if (row == numRows)
{
if (numRows == 0)
newRSize.y = bounds.origin.y;
else
{
rSize = (MiscRowSize *)[rowSizes elementAt:row-1];
newRSize.y = rSize->y + rSize->height + intercell.height;
}
}
else
{
rSize = (MiscRowSize *)[rowSizes elementAt:row];
newRSize.y = rSize->y;
}
newRSize.height = cellSize.height;
[super insertRowAt:row];
[rowSizes insertElement:&newRSize at:row];
[self _Misc_moveRowsDownBy:newRSize.height + intercell.height
startingAt:row+1
];
return self;
}
- removeColAt:(int)col andFree:(BOOL)flag
// Keep the storage in synch
{
MiscColumnSize *cSize;
NXCoord diff;
if ((col >= numCols) || (col < 0)) {
return nil;
}
[super removeColAt:col andFree:flag];
cSize = (MiscColumnSize *)[columnSizes elementAt:col];
diff = cSize->width;
[columnSizes removeElementAt:col];
[self _Misc_moveColumnsRightBy:0.0 - diff - intercell.width
startingAt:col];
return self;
}
- removeRowAt:(int)row andFree:(BOOL)flag
// Keep the storage in synch
{
MiscRowSize *rSize;
NXCoord diff;
if ((row >= numRows) || (row < 0)) {
return nil;
}
[super removeRowAt:row andFree:flag];
rSize = (MiscRowSize *)[rowSizes elementAt:row];
diff = rSize->height;
[rowSizes removeElementAt:row];
[self _Misc_moveRowsDownBy:0.0 - diff - intercell.height startingAt:row];
return self;
}
- drawSelf:(const NXRect *)rects:(int)rectCount
// We do our own drawing because we need to draw our cells in diverse
// rectangles
{
int i, j;
NXRect cFrm;
[window disableFlushWindow];
// the background (if any)
if (backgroundGray != -1.0) {
PSsetgray(backgroundGray);
if (rectCount==1) {
NXRectFill(&(rects[0]));
} else {
NXRectFill(&(rects[1]));
NXRectFill(&(rects[2]));
}
}
// The cells
for (i=0; i<numRows; i++) {
for (j=0; j<numCols; j++) {
[self getCellFrame:&cFrm at:i:j];
if (rectCount == 1) {
if (NXIntersectsRect(&(rects[0]), &cFrm)) {
[self drawCellAt:i:j];
}
} else {
if ((NXIntersectsRect(&(rects[1]), &cFrm)) ||
(NXIntersectsRect(&(rects[2]), &cFrm))) {
[self drawCellAt:i:j];
}
}
}
}
[window reenableFlushWindow];
[window flushWindow];
return self;
}
- getCellFrame:(NXRect *)theRect at:(int)row:(int)col
// Calculate and return the rect used to display the cell at the given
// row and column
{
MiscColumnSize *cSize;
MiscRowSize *rSize;
if (col < numCols) {
cSize = (MiscColumnSize *)[columnSizes elementAt:col];
theRect->origin.x = cSize->x;
theRect->size.width = cSize->width;
} else {
int num = col - numCols;
cSize = (MiscColumnSize *)[columnSizes lastElement];
theRect->origin.x = cSize->x +
(num * (cellSize.width + intercell.width));
theRect->size.width = cellSize.width;
}
if (row < numRows) {
rSize = (MiscRowSize *)[rowSizes elementAt:row];
theRect->origin.y = rSize->y;
theRect->size.height = rSize->height;
} else {
int num = row - numRows;
rSize = (MiscRowSize *)[rowSizes lastElement];
theRect->origin.y = rSize->y +
(num * (cellSize.height + intercell.height));
theRect->size.height = cellSize.height;
}
return self;
}
- getRow:(int *)row andCol:(int *)col forPoint:(const NXPoint *)aPoint
// Calculate the row and column of the cell which contains the given point
{
MiscColumnSize *cSize;
MiscRowSize *rSize;
int i;
*row = -1;
*col = -1;
if ((aPoint->x < bounds.origin.x) ||
(aPoint->x > bounds.origin.x + bounds.size.width) ||
(aPoint->y < bounds.origin.y) ||
(aPoint->y > bounds.origin.y + bounds.size.height)) {
return nil;
}
for (i=0; i<numCols; i++) {
cSize = (MiscColumnSize *)[columnSizes elementAt:i];
if ((aPoint->x >= cSize->x) &&
(aPoint->x <= cSize->x + cSize->width)) {
*col = i;
break;
}
}
for (i=0; i<numRows; i++) {
rSize = (MiscRowSize *)[rowSizes elementAt:i];
if ((aPoint->y >= rSize->y) &&
(aPoint->y <= rSize->y + rSize->height)) {
*row = i;
break;
}
}
return ((*row == -1) || (*col == -1)) ? nil : self;
}
- setIntercell:(const NXSize *)aSize
// Keep the storage in synch
{
NXCoord xDiff = aSize->width - intercell.width;
NXCoord yDiff = aSize->height - intercell.height;
MiscRowSize *rSize;
MiscColumnSize *cSize;
int i;
for (i=1; i<numRows; i++) {
rSize = (MiscRowSize *)[rowSizes elementAt:i];
rSize->y += (yDiff * i);
}
for (i=1; i<numCols; i++) {
cSize = (MiscColumnSize *)[columnSizes elementAt:i];
cSize->x += (xDiff * i);
}
return [super setIntercell:aSize];
}
- write:(NXTypedStream *)typedStream
// Write our ivars
{
[super write:typedStream];
NXWriteObject(typedStream, columnSizes);
NXWriteObject(typedStream, rowSizes);
return self;
}
- read:(NXTypedStream *)typedStream
// Read our ivars
{
int classVersion;
[super read:typedStream];
classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME);
switch (classVersion) {
case 0: // First version.
columnSizes = NXReadObject(typedStream);
rowSizes = NXReadObject(typedStream);
break;
default:
NXLogError("[%s read:] class version %d cannot read "
"instances archived with version %d",
CLASS_NAME, CLASS_VERSION, classVersion);
[self setupStorage:numRows :numCols];
break;
}
return self;
}
// ********************Overridden private methods***********************
// *****************that I'm going to hell for using********************
// These methods are used by Matrix's mouseDown:. Doing the whole
// mouseDown: method over would have been a royal pain in the butt,
// so I cheated.
- (BOOL)_mouseHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
{
NXPoint point;
id ret;
point = *forpoint;
[self convertPoint:&point fromView:nil];
ret = [self getRow:row andCol:col forPoint:&point];
if (ret == nil)
return NO;
return YES;
}
- (BOOL)_loopHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
{
NXPoint point;
id ret;
point = *forpoint;
[self convertPoint:&point fromView:nil];
ret = [self getRow:row andCol:col forPoint:&point];
if (ret == nil)
return NO;
return YES;
}
- (BOOL)_radioHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
{
NXPoint point;
id ret;
point = *forpoint;
[self convertPoint:&point fromView:nil];
ret = [self getRow:row andCol:col forPoint:&point];
if (ret == nil)
return NO;
return YES;
}
- sizeRowsToFitCells
{
NXRect veryBig;
NXSize size;
NXRect myFrame;
NXCoord maxHeight;
NXCoord offset = 0.0;
MiscRowSize *rSize;
int i,j;
veryBig.size.width = cellSize.width;
veryBig.size.height = MAXFLOAT;
[self getFrame:&myFrame];
for (i = 0; i < numRows; i++)
{
maxHeight = 0.0;
rSize = (MiscRowSize *)[rowSizes elementAt:i];
rSize->y = offset;
for (j = 0; j < numCols; j++)
{
[[self cellAt:i :j] calcCellSize:&size inRect:&veryBig];
if (size.height > maxHeight)
maxHeight = size.height;
}
rSize->height = maxHeight;
offset += maxHeight + intercell.height;
}
myFrame.size.height = offset;
[self setFrame:&myFrame];
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
NXRect oldFrame;
NXCoord dx, dy;
float sx, sy;
printf ("sizeTo\n");
[self getFrame:&oldFrame];
[super sizeTo:width :height];
dx = width - oldFrame.size.width;
dy = height - oldFrame.size.height;
if ([self doesAutosizeCells] && (numRows > 0) && (numCols > 0))
{
NXCoord offset;
int i;
MiscRowSize *rSize;
MiscColumnSize *cSize;
sx = 1 + (dx/(oldFrame.size.width - (numRows - 1)*intercell.width));
sy = 1 + (dy/(oldFrame.size.height - (numCols - 1)*intercell.height));
for (i=0, offset = 0.0; i < numRows; i++)
{
rSize = (MiscRowSize *)[rowSizes elementAt:i];
rSize->y = offset;
rSize->height *= floor(sy+0.5);
offset += rSize->height + intercell.height;
}
for (i=0, offset = 0.0; i < numCols; i++)
{
cSize = (MiscColumnSize *)[columnSizes elementAt:i];
cSize->x = offset;
cSize->width *= sx;
offset += cSize->width + intercell.width;
}
}
return self;
}
@end
@implementation Storage(MiscLastElementCategory)
- (void *)lastElement
// A little shortcut
{
return [self elementAt:numElements-1];
}
@end